#include "execOp.h"

void exec_STA(int i)
{
	int deplacement=0; 
	sscanf(p_code->codes[i]->value, "%d", &deplacement);
	releaseBase(pExecution, deplacement);
}

void exec_LBA(int i)
{
	int deplacement=0; 
	sscanf(p_code->codes[i]->value, "%d", &deplacement);
	setBase(pExecution, deplacement);

	int j;
	for(j=0; j<pExecution->deplacement; ++j)
	{
		if(strcmp(pExecution->base[j]->nom, "LIT")==0)
		{
			int typeI;

			switch(pExecution->base[j]->typeLiteral)
			{
				case t_entier:
					typeI=var_entier;
					break;

				case t_reel:
					typeI=var_reel;
					break;

				case t_char:
					typeI=var_char;
					break;

				case t_string:
					typeI=var_string;
					break;

				case t_byte:
					typeI=var_byte;
					break;
					
				case t_boolean:
					typeI=var_boolean;
					break;

				default:
					typeI=-1;
					break;
			}

			pExecution->base[j]->typeIdentificateur=typeI;
		}
	}
}

int exec_CAL(int i)
{
	int start=0; 
	sscanf(p_code->codes[i]->value, "%d", &start);
	char val[5]; 
	sprintf(val, "%d", i+1);
	empiler(pLigne, "Ligne", val, -1, -1, "Aucun");
	return start;
}

/*Debut programme principal*/
void exec_MAI(int line)
{}

int exec_RET(int i)
{
	struct element *ligne=depiler(pLigne);
	int ret=0;
	sscanf(ligne->valeur, "%d", &ret);
	return ret;
}

void exec_INC(int i)
{
	int symboleLine=0; 
	sscanf(p_code->codes[i]->value, "%d", &symboleLine);
	
	if(symboleLine!=-1)
	{
		struct symbole *select=chercherUnSymbolePosition(tableSymbole, symboleLine);
		empiler(pExecution, select->nom, select->valeur, select->typeIdentificateur, select->typeLiteral, select->nomEmplacement);
		select->ptrPile=pExecution->deplacement-1;
	}
	else
		depiler(pExecution);
}

void exec_OUT(int i)
{
	
	struct element *ligne=depiler(pExecution);
	if(strcmp(ligne->valeur, "\\n")==0)
		printf("\n");
	else
	{
		printf("%s", ligne->valeur);
		fflush(stdin);
	}
}

int exec_INP(int i)
{	
	char *line=malloc(256*sizeof(char)); int nRead=0;
	nRead=read(1, line, 256*sizeof(char));
	line[nRead-1]='\000';

	int entier, typeI, typeL;
	double reel;
	char c;
	char val[256], str[256];

	int deplacement=0; 
	sscanf(p_code->codes[i]->value, "%d", &deplacement);

	switch(p_code->codes[i]->type)
	{
		case t_entier:
			if(sscanf(line, "%d", &entier)!=0)
			{
				if(strchr(line, '.')!=NULL)
				{
					entier=(int) entier;
					sprintf(line, "%d", entier);
				}

				typeI=cst_entier;
				typeL=t_entier;
			}
			else return ER_INP;
			break;
		
		case t_byte:
			if(sscanf(line, "%d", &entier)!=0)
			{
				typeI=cst_byte;
				typeL=t_byte;
			}
			else return ER_INP;
			break;

		case t_reel:
			if(sscanf(line, "%lf", &reel)!=0)
			{
				if(strchr(line, '.')==NULL)
				{ 
					reel=(double) reel;
					sprintf(line, "%lf", reel);
				}
				typeI=cst_reel;
				typeL=t_reel;
			}
			else return ER_INP;
			break;

		case t_char:
			if(sscanf(line, "%c", &c)!=0)
			{
				typeI=cst_char;
				typeL=t_char;
			}
			else return ER_INP;
			break;

		case t_string:
			if(sscanf(line, "%s", str)!=0)
			{
				typeI=cst_string;
				typeL=t_string;
			}
			else return ER_INP;
			break;

		default:
			return ER_INP;
	}

	empiler(pExecution, "Result INP", line, typeI, typeL, pExecution->base[deplacement]->localisation);

	free(line);
	return 0;
}

void exec_LOD(int i)
{
	int deplacement=0; 
	sscanf(p_code->codes[i]->value, "%d", &deplacement);
	
	empiler(pExecution, pExecution->base[deplacement]->nom, pExecution->base[deplacement]->valeur, pExecution->base[deplacement]->typeIdentificateur, pExecution->base[deplacement]->typeLiteral, pExecution->base[deplacement]->localisation);
}

void exec_LIT(int i)
{
	empiler(pExecution, "LIT", p_code->codes[i]->value, -1, p_code->codes[i]->type, "Temporaire");
}

int exec_OPR(int i)
{
	char buffer[1024], result[128];
	struct element *first=depiler(pExecution), *second=depiler(pExecution);
	int typeOperation=0, flag, resTypeOperation;
	sscanf(p_code->codes[i]->value, "%d", &typeOperation);

	int *i1, *i2, *ires;
	double *d1, *d2, *dres;
	char c1, c2, cres;
	char str1[128], str2[128];

	i1=(int*) malloc(1*sizeof(int));
	i2=(int*) malloc(1*sizeof(int));
	ires=(int*) malloc(1*sizeof(int));

	d1=(double*) malloc(1*sizeof(double));
	d2=(double*) malloc(1*sizeof(double));
	dres=(double*) malloc(1*sizeof(double));

	if(typeOperation==0 || typeOperation==1 || typeOperation==2 || typeOperation==3)
	{
		switch(first->typeLiteral)
		{
			case t_entier:

				if(second->typeLiteral==t_entier || second->typeLiteral==t_byte)
				{
					// Cas entier vs entier ou entier vs byte
					sscanf(first->valeur, "%d", i1);
					sscanf(second->valeur, "%d", i2);

					switch(typeOperation)
					{
						case 0: (*ires)=(*i1)+(*i2); break;
						case 1: (*ires)=(*i2)-(*i1); break;
						case 2: (*ires)=(*i1)*(*i2); break;
						case 3: (*dres)=(double)(*i2)/(double)(*i1); break;
						default: return ER_OPERATION;
					}
					
					if(typeOperation!=3)
					{
						resTypeOperation=t_entier;
						sprintf(result, "%d", (*ires));
					}
					else
					{
						resTypeOperation=t_reel;
						sprintf(result, "%lf", (*dres));
					}
				}
				else if(second->typeLiteral==t_reel)
				{
					// Cas entier vs reel
					sscanf(first->valeur, "%d", i1);
					sscanf(second->valeur, "%lf", d2); 

					switch(typeOperation)
					{
						case 0: (*dres)=(*i1)+(*d2); break;
						case 1: (*dres)=(*d2)-(*i1); break;
						case 2: (*dres)=(*i1)*(*d2); break;
						case 3: (*dres)=(*d2)/(*i1); break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%lf", (*dres));
					resTypeOperation=t_reel;
				}					
				else return ER_TYPE;
				
				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_reel:

				// cst_reel vs cst_entier ou cst_reel vs var_entier
				if(second->typeLiteral==t_entier)
				{
					// Cas reel vs entier
					sscanf(first->valeur, "%lf", d1);
					sscanf(second->valeur, "%d", i2);
					
					switch(typeOperation)
					{
						case 0: (*dres)=(*d1)+(*i2); break;
						case 1: (*dres)=(*i2)-(*d1); break;
						case 2: (*dres)=(*d1)*(*i2); break;
						case 3: (*dres)=(double)(*i2)/(*d1); break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%lf", (*dres));
				}
				else if(second->typeLiteral==t_reel)
				{
					// Cas reel vs reel
					sscanf(first->valeur, "%lf", d1);
					sscanf(second->valeur, "%lf", d2);
					
					switch(typeOperation)
					{
						case 0: (*dres)=(*d1)+(*d2); break;
						case 1: (*dres)=(*d2)-(*d1); break;
						case 2: (*dres)=(*d1)*(*d2); break;
						case 3: (*dres)=(*d2)/(*d1); break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%lf", (*dres));
				}
				else return ER_TYPE;


				resTypeOperation=t_reel;
				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_string:

				if(typeOperation==0)
				{
					resTypeOperation=t_string;
					if(second->typeLiteral==t_string) sprintf(result, "%s%s", second->valeur, first->valeur);
					else if(second->typeLiteral==t_char) sprintf(result, "%c%s", second->valeur[0], first->valeur);
					else return ER_TYPE;
				}
				else return ER_TYPE;

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_char:
		
				if(typeOperation==0)
				{
					resTypeOperation=t_string;
					if(second->typeLiteral==t_string) sprintf(result, "%s%c", second->valeur, first->valeur[0]);
					else if(second->typeLiteral==t_char) sprintf(result, "%c%c", second->valeur[0], first->valeur[0]);
					else return ER_TYPE;
				}
				else return ER_TYPE;

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_byte:

				if(second->typeLiteral==t_entier) resTypeOperation=t_entier;
				else if(second->typeLiteral==t_byte) resTypeOperation=t_byte;

				sscanf(first->valeur, "%d", i1);
				sscanf(second->valeur, "%d", i2);
				
				switch(typeOperation)
				{
					case 0: (*ires)=(*i1)+(*i2); break;
					case 1: (*ires)=(*i2)-(*i1); break;
					case 2: (*ires)=(*i1)*(*i2); break;
					case 3: (*dres)=(double)(*i2)/(double)(*i1); break;
					default: return ER_OPERATION;
				}

				if(typeOperation!=3)
				{
					resTypeOperation=t_entier;
					sprintf(result, "%d", (*ires));
				}
				else
				{
					resTypeOperation=t_reel;
					sprintf(result, "%lf", (*dres));
				}

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			default:
				return ER_TYPE;
		}
	}
	else if(typeOperation==4 || typeOperation==5 || typeOperation==6 || typeOperation==7 || typeOperation==8 || typeOperation==9)
	{
		resTypeOperation=t_boolean;

		switch(first->typeLiteral)
		{
			case t_entier:

				if(second->typeLiteral==t_entier || second->typeLiteral==t_byte)
				{
					// Cas entier vs entier ou entier vs byte
					sscanf(first->valeur, "%d", i1);
					sscanf(second->valeur, "%d", i2);

					switch(typeOperation)
					{
						case 4: (*ires)=(*i1)>(*i2); break;
						case 5: (*ires)=(*i1)>=(*i2); break;
						case 6: (*ires)=(*i1)<(*i2); break;
						case 7: (*ires)=(*i1)<=(*i2); break;
						case 8: (*ires)=(*i1)!=(*i2); break;
						case 9: (*ires)=(*i1)==(*i2); break;
						default: return ER_OPERATION;
					}
							
					sprintf(result, "%d", (*ires));
					resTypeOperation=t_entier;
				}
				else if(second->typeLiteral==t_reel)
				{
					// Cas entier vs reel
					sscanf(first->valeur, "%d", i1);
					sscanf(second->valeur, "%lf", d2);
					
					switch(typeOperation)
					{
						case 4: (*ires)=(*i1)>(*d2); break;
						case 5: (*ires)=(*i1)>=(*d2); break;
						case 6: (*ires)=(*i1)<(*d2); break;
						case 7: (*ires)=(*i1)<=(*d2); break;
						case 8: (*ires)=(*i1)!=(*d2); break;
						case 9: (*ires)=(*i1)==(*d2); break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%d", (*ires));
					resTypeOperation=t_reel;
				}					
				else return ER_TYPE;
				
				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_reel:

				// cst_reel vs cst_entier ou cst_reel vs var_entier
				if(second->typeLiteral==t_entier)
				{
					// Cas reel vs entier
					sscanf(first->valeur, "%lf", d1);
					sscanf(second->valeur, "%d", i2);
					
					switch(typeOperation)
					{
						case 4: (*ires)=(*d1)>(*i2); break;
						case 5: (*ires)=(*d1)>=(*i2); break;
						case 6: (*ires)=(*d1)<(*i2); break;
						case 7: (*ires)=(*d1)<=(*i2); break;
						case 8: (*ires)=(*d1)!=(*i2); break;
						case 9: (*ires)=(*d1)==(*i2); break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%d", (*ires));
				}
				else if(second->typeLiteral==t_reel)
				{
					// Cas reel vs reel
					sscanf(first->valeur, "%lf", d1);
					sscanf(second->valeur, "%lf", d2);
					
					switch(typeOperation)
					{
						case 4: (*ires)=(*d1)>(*d2); break;
						case 5: (*ires)=(*d1)>=(*d2); break;
						case 6: (*ires)=(*d1)<(*d2); break;
						case 7: (*ires)=(*d1)<=(*d2); break;
						case 8: (*ires)=(*d1)!=(*d2); break;
						case 9: (*ires)=(*d1)==(*d2); break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%d", (*ires));
				}
				else return ER_TYPE;

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_char:

				if(second->typeLiteral==t_char)
				{	
					c1=second->valeur[0];
					c2=first->valeur[0];
					
					switch(typeOperation)
					{
						case 4: (*ires)=c2>c1; break;
						case 5: (*ires)=c2>=c1; break;
						case 6: (*ires)=c2<c1; break;
						case 7: (*ires)=c2<=c1; break;
						case 8: (*ires)=c2!=c1; break;
						case 9: (*ires)=c2==c1; break;
						default: return ER_OPERATION;
					}

					sprintf(result, "%d", (*ires));
				}
				else if(second->typeLiteral==t_string)
				{	
					strcpy(str1, second->valeur);
					strcpy(str2, first->valeur);
					
					switch(typeOperation)
					{
						case 4: 
							// str2 < str1 (attention à l'ordre car pile)
							(*ires)=strcmp(str2, str1); 
					
							if((*ires)==1) flag=1;
							break;

						case 5: 
	
							(*ires)=strcmp(str2, str1);

							if((*ires)>=0) flag=1; 
							break;

						case 6:
					
							(*ires)=strcmp(str2, str1);

							if((*ires)<0) flag=1; 
							break;

						case 7:
			
							(*ires)=strcmp(str2, str1);

							if((*ires)<=0) flag=1; 
							break;

						case 8: 

							(*ires)=strcmp(str2, str1);

							if((*ires)!=0) flag=1; 
							break;

						case 9: 

							(*ires)=strcmp(str2, str1);

							if((*ires)==0) flag=1; 
							break;

						default: return ER_OPERATION;
					}

					sprintf(result, "%d", flag);
				}
				else return ER_TYPE;

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_string:

				if(second->typeLiteral==t_string || second->typeLiteral==t_char)
				{	
					strcpy(str1, second->valeur);
					strcpy(str2, first->valeur);
					
					switch(typeOperation)
					{
						case 4: 
							// str2 < str1 (attention à l'ordre car pile)
							(*ires)=strcmp(str2, str1); 
					
							if((*ires)==1) flag=1;
							break;

						case 5: 
	
							(*ires)=strcmp(str2, str1);

							if((*ires)>=0) flag=1; 
							break;

						case 6:
					
							(*ires)=strcmp(str2, str1);

							if((*ires)<0) flag=1; 
							break;

						case 7:
			
							(*ires)=strcmp(str2, str1);

							if((*ires)<=0) flag=1; 
							break;

						case 8: 

							(*ires)=strcmp(str2, str1);

							if((*ires)!=0) flag=1; 
							break;

						case 9: 
						
							(*ires)=strcmp(str2, str1);
							if((*ires)==0) flag=1; 
							break;

						default: return ER_OPERATION;
					}

					sprintf(result, "%d", flag);
				}
				else return ER_TYPE;

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;

			case t_byte:

				if(second->typeLiteral==t_entier) resTypeOperation=t_entier;
				else if(second->typeLiteral==t_byte) resTypeOperation=t_byte;

				sscanf(first->valeur, "%d", i1);
				sscanf(second->valeur, "%d", i2);
				
				switch(typeOperation)
				{
					case 4: (*ires)=(*i1)>(*i2); break;
					case 5: (*ires)=(*i1)>=(*i2); break;
					case 6: (*ires)=(*i1)<(*i2); break;
					case 7: (*ires)=(*i1)<=(*i2); break;
					case 8: (*ires)=(*i1)!=(*i2); break;
					case 9: (*ires)=(*i1)==(*i2); break;
					default: return ER_OPERATION;
				}

				sprintf(result, "%d", (*ires));

				empiler(pExecution, "OPR result", result, resTypeOperation, resTypeOperation, "Temporaire");
				break;
			default:
				return ER_TYPE;
		}
	}
	else return ER_TYPE;

	free(i1);
	free(i2);
	free(ires);
	free(d1);
	free(d2);
	free(dres);

	return 0;
}

// Saut sans flag
int exec_JMP(int i)
{
	int ret=0;
	sscanf(p_code->codes[i]->value, "%d", &ret);
	return ret;
}

// Saut avec flag
int exec_JPC(int i)
{
	// i JPC flag, N°ligne
	int line=i, flagValue=pExecution->flag, value=p_code->codes[i]->type;

	if(flagValue==value)
		sscanf(p_code->codes[i]->value, "%d", &line);
	else line=i+1;

	return line;
}

void exec_SFL(int i)
{
	struct element *flag=depiler(pExecution);
	int flagValue;
	
	sscanf(flag->valeur, "%d", &flagValue);
	pExecution->flag=flagValue;
}

int exec_STO(int i)
{
	int deplacement=0; 
	sscanf(p_code->codes[i]->value, "%d", &deplacement);

	//1 STO N, depl commentaire
	int ok=0;
	struct element *src=depiler(pExecution);
	char buffer[1024], result[128];

	// Variable de conversion
	int ilit, ires;
	double dlit, dres;

	struct element *dest=pExecution->base[deplacement]; 

	if(dest->typeIdentificateur==cst_entier || dest->typeIdentificateur==cst_reel || dest->typeIdentificateur==cst_char || dest->typeIdentificateur==cst_byte || dest->typeIdentificateur==cst_string || dest->typeIdentificateur==cst_boolean) 				return ER_AFFECTATION_STO;
	
	switch(dest->typeIdentificateur)
	{
		case var_entier:
			// cst_entier vs cst_entier ou cst_entier vs var_entier idem avec reel
			if(src->typeLiteral==t_entier){ strcpy(result, src->valeur); ok=1; }
			else if(src->typeLiteral==t_reel)
			{
				sscanf(src->valeur, "%lf", &dlit);
				ires=(int) dlit;
				sprintf(result, "%d", ires);
				ok=1;
			}
			break;

		case var_reel:
			// cst_reel vs cst_entier ou cst_reel vs var_entier
			if(src->typeLiteral==t_entier)
			{
				sscanf(src->valeur, "%d", &ilit);
				dres=(double) ilit;
				sprintf(result, "%lf", dres);
				ok=1;
			}
			else if(src->typeLiteral==t_reel){ strcpy(result, src->valeur); ok=1; }	
			break;

		case var_boolean:
			if(src->typeLiteral==t_boolean){ strcpy(result, src->valeur); ok=1; }
			break;

		case var_string:
			if(src->typeLiteral==t_string || src->typeLiteral==t_char){ strcpy(result, src->valeur); ok=1; }		
			break;

		case var_char:
			if(src->typeLiteral==t_char){ strcpy(result, src->valeur); ok=1; }		
			break;

		case var_byte:
			if(src->typeLiteral==t_entier || src->typeLiteral==t_byte){ strcpy(result, src->valeur); ok=1; }		
			break;
	}
	

	if(ok==1)
	{
		strcpy(pExecution->base[deplacement]->valeur, result); 
		return 0;
	}
	else return ER_TYPE;
}

int typePcode(char comparaison[5])
{
	if(strcmp(comparaison, "+")==0) return 0;
	else if(strcmp(comparaison, "-")==0) return 1;
	else if(strcmp(comparaison, "*")==0) return 2;
	else if(strcmp(comparaison, "/")==0) return 3;
	else if(strcmp(comparaison, "<")==0) return 4;
	else if(strcmp(comparaison, "<=")==0) return 5;
	else if(strcmp(comparaison, ">")==0) return 6;
	else if(strcmp(comparaison, ">=")==0) return 7;
	else if(strcmp(comparaison, "<>")==0) return 8;
	else if(strcmp(comparaison, "=")==0) return 9;
	else return -1;
}
